package impl

import (
	factory2 "apibe/grpc/rome/v1/factory"
	"apibe/grpc/rome/v1/share/crypt"
	"apibe/grpc/rome/v1/share/db"
	"context"
	"encoding/json"
	"fmt"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"time"
)

type Design factory2.Design

var ignoreDeleted = bson.M{"$lt": factory2.Deleted}

func (d *Design) UpsertOne(claims *crypt.CustomClaims) (*mongo.UpdateResult, error) {
	ctx := context.Background()
	option := &options.UpdateOptions{}
	if d.ID == primitive.NilObjectID {
		d.ID = primitive.NewObjectID()
		option.SetUpsert(true)
	}
	d.HoldUser = claims.UserName
	d.FixDate = time.Now().Unix()
	d.Status = factory2.NeedCheck
	one, err := db.GetMongoCollection(db.CollectionDesign).UpdateOne(ctx, bson.M{"_id": d.ID}, bson.M{"$set": d}, option)
	if err != nil {
		return nil, err
	}
	{ // 日志
		bytes, _ := json.Marshal(d)
		factory2.OperationLogger(factory2.Waring, one.UpsertedID, claims, fmt.Sprintf("Design UpsertOne %v", string(bytes)))
	}
	return one, nil
}

func (d *Design) AddLogger() {
	if d.ID == primitive.NilObjectID {
		return
	} else {
		logs, err := factory2.OperationLoggerFindManyIds(d.ID)
		if err != nil {
			return
		}
		d.Logger = *logs
	}
}

func (*Design) UpdateOne(filter map[string]interface{}, update map[string]interface{}, claims *crypt.CustomClaims) (*mongo.UpdateResult, error) {
	ctx := context.Background()
	one, err := db.GetMongoCollection(db.CollectionDesign).UpdateOne(ctx, filter, update)
	if err != nil {
		return nil, err
	}
	{ // 日志
		bytes1, _ := json.Marshal(filter)
		bytes2, _ := json.Marshal(update)
		factory2.OperationLogger(factory2.Waring, one.UpsertedID, claims, fmt.Sprintf("Design UpdateOne filter: %v update: %v", string(bytes1), string(bytes2)))
	}
	return one, nil
}

func (*Design) UpdateMany(filter map[string]interface{}, update map[string]interface{}, claims *crypt.CustomClaims) (*mongo.UpdateResult, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel() // 修改操作超时时间为60秒
	many, err := db.GetMongoCollection(db.CollectionDesign).UpdateMany(ctx, filter, update)
	if err != nil {
		return nil, err
	}
	{
		// 日志收集
		filterBytes, _ := json.Marshal(filter)
		updateBytes, _ := json.Marshal(update)
		manyBytes, _ := json.Marshal(many)
		factory2.OperationLogger(factory2.Err, many.UpsertedID, claims, fmt.Sprintf("Design UpdateMany filter: %v update: %v many: %v", string(filterBytes), string(updateBytes), string(manyBytes)))
	}
	return many, nil
}

func (*Design) UpdateStatus(id primitive.ObjectID, claims *crypt.CustomClaims, status factory2.Status) (*mongo.UpdateResult, error) {
	ctx := context.Background()
	update := bson.M{"$set": bson.M{"status": status}}
	result, err := db.GetMongoCollection(db.CollectionDesign).UpdateByID(ctx, id, update)
	if err != nil {
		//fmt.println(err)
		return nil, err
	}
	{
		// 日志搜集
		factory2.OperationLogger(factory2.Waring, result.UpsertedID, claims, fmt.Sprintf("Design RemoveIdLogic RemoveId: %v", result.UpsertedID))
	}
	return result, err
}

func (*Design) RemoveIdPhysics(id primitive.ObjectID, claims *crypt.CustomClaims) (*mongo.DeleteResult, error) {
	ctx := context.Background()
	update := make(map[string]interface{})
	update["_id"] = id
	var inD Design
	_ = db.GetMongoCollection(db.CollectionDesign).FindOne(ctx, bson.M{"_id": id}).Decode(&inD)
	one, err := db.GetMongoCollection(db.CollectionDesign).DeleteOne(ctx, update)
	if err != nil {
		return nil, err
	}
	{
		bytes, _ := json.Marshal(inD)
		factory2.OperationLogger(factory2.Err, id, claims, fmt.Sprintf("Design RemoveIdPhysics RemoveId: %v Design: %v", id, string(bytes)))
	}
	return one, nil
}

func (*Design) FindOneId(id primitive.ObjectID) *mongo.SingleResult {
	ctx := context.Background()
	result := db.GetMongoCollection(db.CollectionDesign).FindOne(ctx, bson.M{"_id": id, "status": ignoreDeleted})
	return result
}

func (*Design) FindOneFilter(filter map[string]interface{}) *mongo.SingleResult {
	ctx := context.Background()
	filter["status"] = ignoreDeleted
	result := db.GetMongoCollection(db.CollectionDesign).FindOne(ctx, filter)
	return result
}

func (*Design) FindManyFilter(filter map[string]interface{}, page int, pageSize int) (*mongo.Cursor, int64, error) {
	ctx := context.Background()
	option := &options.FindOptions{}
	filter["status"] = ignoreDeleted
	total, err := db.GetMongoCollection(db.CollectionDesign).CountDocuments(ctx, filter)
	if err != nil {
		return nil, 0, err
	}
	option.SetLimit(int64(pageSize))
	option.SetSkip(int64((page - 1) * pageSize))
	option.SetSort(bson.M{"group_name": 1})
	cursor, err := db.GetMongoCollection(db.CollectionDesign).Find(ctx, filter, option)
	if err != nil {
		return nil, 0, err
	}
	return cursor, total, nil
}

func (*Design) Exist(filter map[string]interface{}) bool {
	ctx := context.Background()
	filter["status"] = ignoreDeleted
	err := db.GetMongoCollection(db.CollectionDesign).FindOne(ctx, filter).Err()
	if err != nil || err == mongo.ErrNoDocuments {
		return false
	}
	return true
}
